﻿#include "control.h"
#include "chesspiece.h"

Control::Control(bool &isRed): _isRedTurn(isRed) {
}

// 行走规则
bool Control::canMove(ChessPiece *_s, bool isPerson, qint8 &id, qint8 destRow, qint8 destCol, qint8 killId) {
    if(killId != -1 && _s[id]._isRed == _s[killId]._isRed) {
        if(isPerson) {
            id = killId;
        }
        return false;
    }
    return _canMove(_s, id, destRow, destCol, killId);
}

// 行走规则
bool Control::canMove(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol, qint8 killId) {
    if(killId != -1 && _s[id]._isRed == _s[killId]._isRed) {
        return false;
    }
    return _canMove(_s, id, destRow, destCol, killId);
}

// 行走规则, 内部方法
bool Control::_canMove(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol, qint8 killId) {
    // 对于不同的棋子,建立不同的行走规则
    switch (_s[id]._type) {
        case ChessPiece::JIANG:
            return _canMove_JIANG(_s, id, destRow, destCol);
            break;
        case ChessPiece::CHE:
            return _canMove_CHE(_s, id, destRow, destCol);
            break;
        case ChessPiece::MA:
            return _canMove_MA(_s, id, destRow, destCol);
            break;
        case ChessPiece::XIANG:
            return _canMove_XIANG(_s, id, destRow, destCol);
            break;
        case ChessPiece::SHI:
            return _canMove_SHI(_s, id, destRow, destCol);
            break;
        case ChessPiece::PAO:
            return _canMove_PAO(_s, id, destRow, destCol, killId);
            break;
        case ChessPiece::BING:
            return _canMove_BING(_s, id, destRow, destCol);
            break;
    }
    return false;
}

// 行走规则 - 将
bool Control::_canMove_JIANG(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol) {
    // 目标位置只能在九宫格
    if((destRow > 2 && destRow < 7) || destCol < 3 || destCol > 5) {
        return false;
    }
    // 步长只能为1格
    int dr = destRow - _s[id]._row;
    int dc = destCol - _s[id]._col;
    int dl = qAbs(dr) * 10 + qAbs(dc);          // 这里是一个很有意思的计算方式, 这样可以实现不同棋子的统一计算
    if(dl == 1 || dl == 10) {
        return _againstJiang(_s, id, destCol);
    }
    return false;
}

// 行走规则 - 车
bool Control::_canMove_CHE(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol) {
    // 只能直行
    if(destCol == _s[id]._col || destRow == _s[id]._row) {
        // 检索所有存活棋子, 不能有棋子在 当前棋子位置和目标位置之间
        for(qint8 i = 0; i < 32; ++i) {
            if(!_s[i]._isDead) {
                if((_s[i]._col < qMax(destCol, _s[id]._col) && _s[i]._col > qMin(destCol, _s[id]._col) && destRow == _s[i]._row) ||
                        (_s[i]._row < qMax(destRow, _s[id]._row) && _s[i]._row > qMin(destRow, _s[id]._row) && destCol == _s[i]._col)) {
                    return false;
                }
            }
        }
        // 检查是否产生对将
        if(_moveToAgainst(_s, id, destRow, destCol)) {
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }
}

// 行走规则 - 马
bool Control::_canMove_MA(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol) {
    int dr = destRow - _s[id]._row;
    int dc = destCol - _s[id]._col;
    int dl = qAbs(dr) * 10 + qAbs(dc);          // 这里是一个很有意思的计算方式, 这样可以实现不同棋子的统一计算
    if(dl == 21 || dl == 12) {                  // 步长只能为 "日" 字
        if(-1 == isExistChess(_s, _s[id]._row + dr / 2, _s[id]._col + dc / 2)) {        // 是否绊马蹄
            // 检查是否产生对将
            if(_moveToAgainst(_s, id, destRow, destCol)) {
                return false;
            } else {
                return true;
            }
        }
    }
    return false;
}

// 行走规则 - 象
bool Control::_canMove_XIANG(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol) {
    int dr = destRow - _s[id]._row;
    int dc = destCol - _s[id]._col;
    int dl = qAbs(dr) * 10 + qAbs(dc);          // 这里是一个很有意思的计算方式, 这样可以实现不同棋子的统一计算
    if(dl == 22) {                              // 步长只能为 "田" 字
        if(destRow > 4.5 == _s[id]._isRed) {
            if(-1 == isExistChess(_s, _s[id]._row + dr / 2, _s[id]._col + dc / 2)) {    // 是否绊象蹄
                // 检查是否产生对将
                if(_moveToAgainst(_s, id, destRow, destCol)) {
                    return false;
                } else {
                    return true;
                }
            }
        }
    }
    return false;
}

// 行走规则 - 士
bool Control::_canMove_SHI(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol) {
    // 目标位置只能在九宫格
    if((destRow > 2 && destRow < 7) || destCol < 3 || destCol > 5) {
        return false;
    }
    // 只能斜着走一格
    int dr = destRow - _s[id]._row;
    int dc = destCol - _s[id]._col;
    int dl = qAbs(dr) * 10 + qAbs(dc);          // 这里是一个很有意思的计算方式, 这样可以实现不同棋子的统一计算
    if(dl == 11) {
        // 检查是否产生对将
        if(_moveToAgainst(_s, id, destRow, destCol)) {
            return false;
        } else {
            return true;
        }
        return true;
    }
    return false;
}

// 行走规则 - 炮
bool Control::_canMove_PAO(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol, qint8 killId) {
    // 只能直行
    if(destCol == _s[id]._col || destRow == _s[id]._row) {
        int num = 0;                                                    // 当前棋子位置和目标位置之间,存在棋子的个数
        for(int i = 0; i < 32; ++i) {
            if(!_s[i]._isDead) {
                // 是否有棋子在 当前棋子位置和目标位置之间
                if((_s[i]._col < qMax(destCol, _s[id]._col) && _s[i]._col > qMin(destCol, _s[id]._col) && destRow == _s[i]._row) ||
                        (_s[i]._row < qMax(destRow, _s[id]._row) && _s[i]._row > qMin(destRow, _s[id]._row) && destCol == _s[i]._col)) {
                    ++num;
                }
            }
        }
        if(!num && killId == -1) {                                      // 如果没有棋子并且目标位置没有棋子
            // 检查是否产生对将
            if(_moveToAgainst(_s, id, destRow, destCol)) {
                return false;
            } else {
                return true;
            }
            return true;
        } else if(num == 1) { //如果只有一个棋子
            if(killId != -1 && _s[id]._isRed != _s[killId]._isRed) {    // 隔着一个棋子吃敌方棋子
                //检查是否产生对将
                if(_moveToAgainst(_s, id, destRow, destCol)) {
                    return false;
                } else {
                    return true;
                }
                return true;
            }
        }
    }
    return false;
}

// 行走规则 - 兵
bool Control::_canMove_BING(ChessPiece *_s, qint8 &id, qint8 destRow, qint8 destCol) {
    // 步长只能为1格
    int dr = destRow - _s[id]._row;
    int dc = destCol - _s[id]._col;
    int dl = qAbs(dr) * 10 + qAbs(dc);          // 这里是一个很有意思的计算方式, 这样可以实现不同棋子的统一计算
    int flag = id > 15 ? -1 : 1;                // 定义一个变量  如果红方则为1, 否则为-1
    if(dl == 1 || (dl == 10 && dr != -flag)) {  // 步长只能为1,并且不能后退
        if(_s[id]._row < 4.5 == (id <= 15)) {   // 小兵没有过河
            if(dr == flag) {                    // 小兵没有过河不需要考虑对将
                return true;
            }
        } else {                                // 小兵已经过河
            // 检查是否产生对将
            if(_moveToAgainst(_s, id, destRow, destCol)) {
                return false;
            } else {
                return true;
            }
        }
    }
    return false;
}

// 不能对将
bool Control::_againstJiang(ChessPiece *_s, int id, int destCol) {
    int enemyJiangId = 24 - id;
    // 不能主动对将
    if(destCol == _s[enemyJiangId]._col) {
        memset(boradTable, -1, sizeof(boradTable));
        for(int i = 0; i < 32; ++i) {
            if(!_s[i]._isDead) {
                boradTable[_s[i]._row][_s[i]._col] = i;
            }
        }
        for(int i = _s[4]._row + 1; i < _s[20]._row; ++i) {
            if(boradTable[i][destCol] != -1) {
                return true;
            }
        }
        return false;
    }
    return true;
}

// 其他棋子走棋之后是否产生对将
bool Control::_moveToAgainst(ChessPiece *_s, qint8 id, int destRow, int destCol) {
    qint8 myJiangId = id > 15 ? 20 : 4;
    qint8 mCol = _s[id]._col;
    // 如果杀死敌方将, 则跳出
    if(_s[24 - myJiangId]._col == destCol && _s[24 - myJiangId]._row == destRow) {
        return false;
    }
    memset(boradTable, -1, sizeof(boradTable));
    for(int i = 0; i < 32; ++i) {
        if(!_s[i]._isDead) {
            boradTable[_s[i]._row][_s[i]._col] = i;
        }
    }
    // 当前棋子在两将之间
    bool flag = _s[id]._row > qMin(_s[4]._row, _s[20]._row) && _s[id]._row < qMax(_s[4]._row, _s[20]._row);
    bool afterFlag = destRow > qMin(_s[4]._row, _s[20]._row) && destRow < qMax(_s[4]._row, _s[20]._row);
    if(_s[id]._col == _s[myJiangId]._col && flag) {
        int chessNum = 0;
        for(int i = _s[4]._row + 1; i < _s[20]._row; ++i) {
            if(boradTable[i][mCol] != -1) {
                chessNum++;
            }
        }
        if(chessNum >= 2) { // 自己将和敌方将之间棋子数超过2,不会产生对将
            return false;
        } else if(chessNum == 1 && (destCol != _s[myJiangId]._col || !afterFlag)) { //如果两将之间棋子只有自己一个,并且下一步走法不在同列,则产生对将
            return true;
        }
    }
    return false;   //当前棋子不和自己的将在同一列，不会产生对将
}

// 保存路径
Step *Control::saveStep(ChessPiece *_s, qint8 moveId, qint8 killId, qint8 rowTo, qint8 colTo) {
    Step *step = new Step();
    step->_moveId = moveId;
    step->_killId = killId;
    step->_rowTo = rowTo;
    step->_colTo = colTo;
    step->_rowFrom = _s[moveId]._row;
    step->_colFrom = _s[moveId]._col;
    return step;
}

// 检测指定行和列是否有棋子: 有返回id, 没有返回-1
qint8 Control::isExistChess(ChessPiece *_s, qint8 row, qint8 col) {
    for(int i = 0; i < 32; ++i) {
        if(!_s[i]._isDead && _s[i]._col == col && _s[i]._row == row) {
            return i;
        }
    }
    return -1;
}

// 移动棋子
void Control::moveChess(ChessPiece *_s, const Step *const step) {
    moveChess(_s, step->_moveId, step->_killId, step->_rowTo, step->_colTo);
}

// 移动棋子
void Control::moveChess(ChessPiece *_s, qint8 moveId, qint8 killId, qint8 rowTo, qint8 colTo) {
    if(killId != -1) {
        _s[killId]._isDead = true;
    }
    _s[moveId]._row = rowTo;
    _s[moveId]._col = colTo;
    _isRedTurn = !_isRedTurn;
}

// 救活棋子
void Control::reSaveChess(ChessPiece *_s, int id) {
    // 将被吃的棋子救活
    if(id != -1) {
        _s[id]._isDead = false;
    }
}
